package top.z.template.parse.ast.expression;

import top.z.template.Context;
import top.z.template.Error;
import top.z.template.Template;
import top.z.template.parse.Ast.Expression;
import top.z.template.parse.Span;

import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
import java.util.Map;

/**
 * Map 或者 Array 访问. 从 Map 或 Array 中获取元素，其中 mapOrArray 是被访问的变量集合, 而 keyOrIndex 是用于查找元素的键(对于Map)或者索引(对于Array).
 * Map 或者 Array 是只读的, 意味着只能从中读取数据, 不能通过这种方式修改它们的元素
 */
public class MapOrArrayAccess extends Expression {

    private final Expression mapOrArray;
    private final Expression keyOrIndex;

    public MapOrArrayAccess(Span span, Expression mapOrArray, Expression keyOrIndex) {
        super(span);
        this.mapOrArray = mapOrArray;
        this.keyOrIndex = keyOrIndex;
    }

    /**
     * 返回Map或者Array的表达式
     */
    public Expression getMapOrArray() {
        return mapOrArray;
    }

    /**
     * 返回一个表达式, 该表达式用作提取Map或Array元素的键或索引
     */
    public Expression getKeyOrIndex() {
        return keyOrIndex;
    }

    @Override
    public Object evaluate(Template template, Context context, OutputStream out) throws IOException {
        Object mapOrArray = getMapOrArray().evaluate(template, context, out);
        if (mapOrArray == null) {
            throw Error.error("Couldn't find map or array in context.", getSpan());
        }

        Object keyOrIndex = getKeyOrIndex().evaluate(template, context, out);
        if (keyOrIndex == null) {
            throw Error.error("Couldn't evaluate key or index.", getKeyOrIndex().getSpan());
        }

        if (!(keyOrIndex instanceof Number)) {
            throw Error.error("List or array index must be an integer, but was " + keyOrIndex.getClass().getSimpleName(), getKeyOrIndex().getSpan());
        }

        // 访问map
        if (mapOrArray instanceof Map) {
            return ((Map<?, ?>) mapOrArray).get(keyOrIndex);
        }

        // 访问list
        int index = ((Number) keyOrIndex).intValue();
        if (mapOrArray instanceof List) {
            return ((List<?>) mapOrArray).get(index);
        }
        // 访问数组
        if (mapOrArray instanceof int[]) {
            return ((int[]) mapOrArray)[index];
        }
        if (mapOrArray instanceof float[]) {
            return ((float[]) mapOrArray)[index];
        }
        if (mapOrArray instanceof double[]) {
            return ((double[]) mapOrArray)[index];
        }
        if (mapOrArray instanceof boolean[]) {
            return ((boolean[]) mapOrArray)[index];
        }
        if (mapOrArray instanceof char[]) {
            return ((char[]) mapOrArray)[index];
        }
        if (mapOrArray instanceof short[]) {
            return ((short[]) mapOrArray)[index];
        }
        if (mapOrArray instanceof long[]) {
            return ((long[]) mapOrArray)[index];
        }

        return ((Object[]) mapOrArray)[index];
    }
}
